package cn.tedu.luban.order.main.service;

import cn.tedu.luban.attach.api.AttachApi;
import cn.tedu.luban.attach.protocol.dto.AttachDTO;
import cn.tedu.luban.attach.protocol.param.AttachUpdateParam;
import cn.tedu.luban.attach.protocol.query.AttachQuery;
import cn.tedu.luban.demand.api.DemandApi;
import cn.tedu.luban.order.common.enums.OrderResultEnum;
import cn.tedu.luban.order.common.enums.OrderStatusEnum;
import cn.tedu.luban.order.main.converter.OrderLogConverter;
import cn.tedu.luban.order.main.repository.OrderLogRepository;
import cn.tedu.luban.order.main.repository.OrderRepository;
import cn.tedu.luban.order.protocol.bo.AttachInfoBO;
import cn.tedu.luban.order.protocol.bo.OrderBO;
import cn.tedu.luban.order.protocol.bo.OrderLogBO;
import cn.tedu.luban.order.protocol.dto.OrderMessageDTO;
import cn.tedu.luban.order.protocol.param.*;
import cn.tedu.luban.order.protocol.query.FrontOrderListQuery;
import cn.tedu.luban.passport.protocol.jwt.UserPrinciple;
import cn.tedu.luban.passport.sdk.security.LubanSecurityContext;
import com.tedu.inn.protocol.ListRecordTotalBO;
import com.tedu.inn.protocol.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Service
@Slf4j
public class OrderService {

    private static final Map<Integer,List<Integer>> STATUS_REGISTRY = new HashMap<>();

    static{
        // map注册器初始化 key: 10 20 50 30
        // 根据业务需求在STATUS_REGISTRY添加状态 10->[20,-30] 20->[50] 50->[50,30] 30->[40]
        List<Integer> target01 = new ArrayList<>();
        target01.add(20);
        target01.add(-30);
        STATUS_REGISTRY.put(10,target01);

        List<Integer> target02 = new ArrayList<>();
        target02.add(50);
        STATUS_REGISTRY.put(20,target02);

        List<Integer> target03 = new ArrayList<>();
        target03.add(50);
        target03.add(30);
        STATUS_REGISTRY.put(50,target03);

        List<Integer> target04 = new ArrayList<>();
        target04.add(40);
        STATUS_REGISTRY.put(30,target04);
    }

    
    @Autowired
    private OrderRepository orderRepository;
    @Autowired
    private OrderLogRepository orderLogRepository;
    @Autowired
    private OrderLogConverter orderLogConverter;

    @Autowired
    private DemandApi demandApi;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public String orderCreate(OrderCreateParam param) throws BusinessException {
        // 1.RPC远程调用 抢单(demand)
        grabRequestOrder(param);
        
        // 2.生成订单(param缺少属性)
        putOrderNoAndStatus(param);
        orderRepository.saveOrder(param);

        // 3.新增订单日志记录
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                param.getUserId(),
                param.getOrderNo(),
                OrderStatusEnum.ORDER_CREATE_SUCCESS);
        orderLogRepository.saveOrderLog(orderLogParam);

        // 4.发送延迟消息
        // 封装消息对象
        Message<String> msg = MessageBuilder.withPayload(param.getOrderNo()).build();
        // 发送延迟消息
        SendResult result = rocketMQTemplate.syncSend("order_delay_topic", msg, 500, 4);
        if(!"SEND_OK".equals(result.getSendStatus().toString())){ // 延迟消息发送失败
            throw new BusinessException("9001","生单失败,延迟消息发送失败");
        }

        return param.getOrderNo();
    }

    private void putOrderNoAndStatus(OrderCreateParam param) throws BusinessException {
        // userId
        Long userId = getUserId();
        param.setUserId(userId);

        // orderNo 保证唯一性
        String orderNo = UUID.randomUUID().toString();
        param.setOrderNo(orderNo);

        // order状态
        // 10-抢单成功 20-签到 30-完成待结算 40-完成 50-施工确认
        param.setStatus(OrderStatusEnum.ORDER_CREATE_SUCCESS.getStatus());
    }

    private void grabRequestOrder(OrderCreateParam param) throws BusinessException {
        String requestOrderNo = param.getRequestOrderNo();
        Boolean aBoolean = demandApi.grabOrder(requestOrderNo);
        if(!aBoolean){
            throw new BusinessException(OrderResultEnum.ORDER_GRAB_FAIL);
        }
    }

    public Long getUserId() throws BusinessException {
        // 获取登录用户
        UserPrinciple user = LubanSecurityContext.getLoginToken();
        // 判断用户是否登录
        if(user == null){
            throw new BusinessException("1000", "身份信息验证失败");
        }
        // 补充userId
        return user.getId();
    }


    public ListRecordTotalBO<OrderBO> orderList(FrontOrderListQuery query) {

        ListRecordTotalBO<OrderBO> listBO = null;
        // 查询行数
        Long total = orderRepository.countOrders(query);
        // 判断是否为空
        if(total == 0){
            listBO = new ListRecordTotalBO<>(null,total);
        }else{
            // 查询分页数据
            List<OrderBO> orderBOS = orderRepository.queryOrders(query);
            listBO = new ListRecordTotalBO<>(orderBOS,total);
        }

        return listBO;
    }

    public OrderBO orderDetail(String orderNo) throws BusinessException {
        // 1.检查订单是否存在,存在返回订单数据,不存在则抛出异常
        OrderBO orderBO = checkEmpty(orderNo);

        // 2.给订单封装 签到时间
        List<OrderLogBO> orderLogs = orderLogRepository.getOrderLogByOrderNo(orderNo);
        if(CollectionUtils.isEmpty(orderLogs)){
            throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        Long operateTime = null;
        for(OrderLogBO orderLog : orderLogs){
            // 没有订单状态,所以只能用操作名称对比
            String operateName = orderLog.getOperateName();
            //if("签到".equals(operateName)){
            if(OrderStatusEnum.ORDER_SIGN_SUCCESS.getMessage().equals(operateName)){
                operateTime = orderLog.getOperateTime();
            }
        }
        orderBO.setSignTime(operateTime);

        //3. RPC远程调用 封装图片信息
        putAttachUrls(orderBO);

        return orderBO;
    }

    @Autowired
    private AttachApi attachApi;
    private void putAttachUrls(OrderBO orderBO) {
        // 查询当前订单所绑定的图片
        AttachQuery query = new AttachQuery();
        // 师傅-BusinessType-100 订单-BusinessType-200
        query.setBusinessType(200);
        query.setBusinessId(orderBO.getId().intValue());

        List<AttachDTO> attachDTOS = attachApi.getAttachInfoByParam(query);
        List<AttachInfoBO> bos = new ArrayList<>();

        for(AttachDTO attachDTO : attachDTOS){
            String url = "http://localhost:8092/static/"+attachDTO.getFileUuid();
            AttachInfoBO bo = new AttachInfoBO();
            bo.setUrl(url);
            bos.add(bo);
        }

        orderBO.setAttachInfoBO(bos);
    }

    private OrderBO checkEmpty(String orderNo) throws BusinessException {
        log.error("orderNo:{}",orderNo);
        OrderBO orderBO = orderRepository.getOrderByOrderNo(orderNo);
        if(orderBO.getId()==null){
           throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        return orderBO;
    }


    public void orderSign(OrderSignParam param) throws BusinessException {
        // 1.获取订单编号
        String orderNo = param.getOrderNo();
        // 验证参数对应的订单是否为空
        OrderBO orderBO = checkEmpty(orderNo);

        // 2.检查定位是否允许签到
        checkLocations();

        // 3.检查流转是否合法
        Integer currentStatus = orderBO.getStatus();
        //Integer targetStatus = 20;
        Integer targetStatus = OrderStatusEnum.ORDER_SIGN_SUCCESS.getStatus();
        checkStatusTransfer(currentStatus,targetStatus);

        // 4.修改订单状态
        OrderParam orderParam = new OrderParam();
        orderParam.setOrderNo(orderNo);
        orderParam.setStatus(targetStatus);
        orderRepository.updateStatus(orderParam);

        // 5.记录日志信息
        Long userId = getUserId();
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                userId,
                orderNo,
                OrderStatusEnum.ORDER_SIGN_SUCCESS);
        orderLogRepository.saveOrderLog(orderLogParam);

    }

    // 检查流程是否合法:参数1-当前状态 参数2-目标状态
    private void checkStatusTransfer(Integer currentStatus, Integer targetStatus) throws BusinessException {

//        if(currentStatus==10 && (targetStatus!=20 && targetStatus!=-30)){
//            // 流转失败
//        }else if(currentStatus==20 && targetStatus!=50){
//            // 流转失败
//        }


        // 策略模式(23种)
        // Map注册器
//        if (STATUS_REGISTRY.containsKey(currentStatus) && STATUS_REGISTRY.get(currentStatus).contains(targetStatus)) {
//            return;
//        }
//        throw new BusinessException(OrderResultEnum.ORDER_STATUS_TRANSFORM_ERROR);

        boolean hasKey = STATUS_REGISTRY.containsKey(currentStatus);
        if(!hasKey){ //没有定义流程
            throw new BusinessException(OrderResultEnum.ORDER_STATUS_TRANSFORM_ERROR);
        }
        List<Integer> destStatuses = STATUS_REGISTRY.get(currentStatus);
        boolean contains = destStatuses.contains(targetStatus);
        if(!contains){ //没有定义流程
            throw new BusinessException(OrderResultEnum.ORDER_STATUS_TRANSFORM_ERROR);
        }

    }

    private void checkLocations() {
    }


    public void orderConfirm(OrderConfirmParam param) throws BusinessException {
        // 1. 检查参数ids值是否为空
        checkEmptyPictures(param);

        // 2. 检查orderNo
        OrderBO orderBO = checkEmpty(param.getOrderNo());

        // 3. 检查订单流转状态
        Integer currentStatus = orderBO.getStatus(); //20
        Integer targetStatus = OrderStatusEnum.ORDER_ATTACH_CONFIRM.getStatus(); //50
        checkStatusTransfer(currentStatus,targetStatus);

        // 4. 判断订单当前状态 \ 更新状态(!=50)
        // !=50 肯定等于20
        if(currentStatus != 50){
            //更新状态
            OrderParam orderParam = new OrderParam();
            orderParam.setOrderNo(param.getOrderNo());
            orderParam.setStatus(targetStatus);
            orderRepository.updateStatus(orderParam);
        }
        // 5. 记录施工确认上传图片的日志
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                getUserId(),
                param.getOrderNo(),
                OrderStatusEnum.ORDER_ATTACH_CONFIRM);

        orderLogRepository.saveOrderLog(orderLogParam);

        // 6. rpc远程调用(绑定图片)
        bindPictures(param,200,orderBO.getId().intValue());
    }

    private void bindPictures(OrderConfirmParam param, int businessType, int businessId) throws BusinessException {
        // 获取图片ids
        List<Long> attachIds = param.getAttachIds();
        // 绑定图片
        List<AttachUpdateParam> attachUpdateParams = new ArrayList<>();
        for(Long attachId : attachIds){
            AttachUpdateParam attachUpdateParam = new AttachUpdateParam();
            attachUpdateParam.setId(attachId.intValue());
            attachUpdateParam.setBusinessType(businessType);
            attachUpdateParam.setBusinessId(businessId);
            attachUpdateParam.setIsCover(0); // 是否为封面(非空)

            attachUpdateParams.add(attachUpdateParam);
        }
        int result = attachApi.batchUpdateAttachByIdList(attachUpdateParams);

        if(result == 0){
            throw new BusinessException(OrderResultEnum.ATTACH_CONFIRM_ERROR);
        }


    }

    private void checkEmptyPictures(OrderConfirmParam param) throws BusinessException {
        List<Long> attachIds = param.getAttachIds();
        if(CollectionUtils.isEmpty(attachIds)){ // 没有图片数据
            throw new BusinessException(OrderResultEnum.ATTACH_CONFIRM_ERROR);
        }
    }

    public void orderDelay(String orderNo) throws BusinessException {
        // 1.验证空订单
        OrderBO orderBO = checkEmpty(orderNo);

        // 2.判断当前状态
        Integer currentStatus = orderBO.getStatus();
        if(currentStatus != 10){ // 已签到
            return;
        }

        // 3.订单 - 超时未签到: a.修改订单状态(-30) b.记录日志 c.归还需求单
        Integer targetStatus = OrderStatusEnum.CANCELLED_BY_EXPIRE.getStatus(); //-30
        // 检查流转状态
        checkStatusTransfer(currentStatus,targetStatus);

        // 4.修改订单状态(-30)
        OrderParam orderParam = new OrderParam();
        orderParam.setOrderNo(orderNo);
        orderParam.setStatus(targetStatus);
        orderRepository.updateStatus(orderParam);
        // 5.记录日志
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                999L, orderNo,OrderStatusEnum.CANCELLED_BY_EXPIRE);
        orderLogRepository.saveOrderLog(orderLogParam);

        // 6.归还需求单 RPC
        Boolean aBoolean = demandApi.returnOrder(orderBO.getRequestOrderNo());
        if(!aBoolean){
            throw new BusinessException("9003","归还需求单失败");
        }


    }

    public void orderFinish(OrderFinishParam param) throws BusinessException {
        // 1.检查orderNo对应订单是否存在
        String orderNo = param.getOrderNo();
        OrderBO orderBO = checkEmpty(orderNo);

        // 2.检查订单流转状态
        Integer currentStatus = orderBO.getStatus();
        Integer targetStatus = OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE.getStatus();
        checkStatusTransfer(currentStatus,targetStatus);

        // 3.更新订单状态
        OrderParam orderParam = new OrderParam();
        orderParam.setOrderNo(orderNo);
        orderParam.setStatus(targetStatus);
        orderRepository.updateStatus(orderParam);

        // 4.日志记录
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                getUserId(), orderNo, OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE);
        orderLogRepository.saveOrderLog(orderLogParam);

        // 5.发送消息
        OrderMessageDTO dto = new OrderMessageDTO();
        BeanUtils.copyProperties(orderBO,dto);
        Message<OrderMessageDTO> message = MessageBuilder.withPayload(dto).build();

        SendResult result = rocketMQTemplate.syncSend("order_finish_topic", message);
        if(!"SEND_OK".equals(result.getSendStatus().toString())){
            throw new BusinessException("9003","订单完结发送消息失败");
        }


    }

    public void orderComplete(String orderNo) throws BusinessException {
        // 检查订单
        OrderBO orderBO = checkEmpty(orderNo);
        // 状态流转
        Integer currentStatus = orderBO.getStatus();
        Integer targetStatus = OrderStatusEnum.ORDER_FINISH.getStatus();
        checkStatusTransfer(currentStatus,targetStatus);
        // 更新订单状态
        OrderParam orderParam = new OrderParam();
        orderParam.setOrderNo(orderNo);
        orderParam.setStatus(targetStatus);
        orderRepository.updateStatus(orderParam);
        // 记录日志
        OrderLogParam orderLogParam
                = orderLogConverter.assembleOrderLogParam(999L, orderNo, OrderStatusEnum.ORDER_FINISH);
        orderLogRepository.saveOrderLog(orderLogParam);



    }
}



















